/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "./runrecord.h"
#include "garmindumpreader.h"

RunRecord::RunRecord()
{
  laps            = QList<Lap>();
  track           = Track();
  track_index     = -1;
  first_lap_index = -1;
  last_lap_index  = -1;
  sport_type      = 0;
  program_type    = 0;
  multisport      = 0;
}

RunRecord::RunRecord(QString filename) {
  GarminDumpReader reader(filename);
  garmin_data *data = reader.get();

  if (data->type != data_Dlist)
  {
    qWarning("GarminRecord: unsuitable garmin_data type. Should be list.");
    garmin_free_data(data);
    return;
  }

  garmin_list *list = (garmin_list*)(data->data);
  initFromData(list);
  garmin_free_data(data);
}

RunRecord::RunRecord(garmin_data* d)
{
  if (d->type != data_Dlist)
  {
    qWarning("GarminRecord: unsuitable garmin_data type. Should be list.");
    return;
  }

  garmin_list *list = (garmin_list*)(d->data);
  initFromData(list);
}

void RunRecord::initFromData(garmin_list* list) {
  garmin_list_node * node;
  node = list->head;

  while (node != NULL)
  {
    int node_type = node->data->type;

    // make sure this is a node
    // then decide what it contains
    // and compose laps/tracks/etc from there
    if(node_type == data_Dlist)
    {
      garmin_data *node_payload = node->data;
      garmin_list *next_list    = (garmin_list*)node_payload->data;

      // lap, aka d1015s (laps)
      if(next_list->head->data->type == data_D1015)
      {
        laps = QList<Lap>();

        // all elements are laps
        garmin_list_node *n = next_list->head;
        while (n != NULL)
        {
          Lap l((D1015*)(n->data->data));
          laps.append(l);
          n = n->next;
        }
      }
       // track, aka single d311 (track index) followed by d304s (waypoints)
      else if(next_list->head->data->type == data_D311)
      {
        QList<Waypoint> points;

        garmin_list_node *n = next_list->head;

        // first element is track info element
        // D311 *track_struct  = (D311*)n->data;
        // rest are waypoints
        n = n->next;

        while (n != NULL)
        {
          Waypoint w((D304*)(n->data->data));
          points.append(w);
          n = n->next;
        }
        track = Track( points);
      }
      else
        qWarning("RunRecord: not sure what to do with list type %d\n",
                  next_list->head->data->type);
    }
    // run, aka d1009 (run info, such as track indices and run type)
    else if (node_type == data_D1009)
    {
      garmin_data* n  = (garmin_data*) node->data;
      D1009 *d        = (D1009*)          n->data;

      track_index     = d->track_index;
      first_lap_index = d->first_lap_index;
      last_lap_index  = d->last_lap_index;
      program_type    = d->program_type;
      sport_type      = d->sport_type;
      multisport      = d->multisport;
    }
    else
      qDebug("RunRecord: not sure what to do with type %d", node_type);

    node = node->next;
  }

  // set tracks for each lap
  // this could be inefficient
  // but we can optimize later

  Lap l;
  foreach(l, laps)
  {
    QTime start = l.get
    
    Position start = l.getBegin();
    qDebug(start.toString().toStdString().c_str());
    qDebug(track.getWaypoint(1).toString().toStdString().c_str());
    printf("%d\n", start.compareTo(start));
    Position end   = l.getEnd();

    QList<Waypoint> list;
    
    int i;
    for (i = 0; i < track.size(); i++)
    {
      Waypoint w = track.getWaypoint(i);
      Position p = w.getPosition();
      if (start.compareTo(p))
      {
        printf("match\n");

        break;
      }
    }

    for ( ; i < track.size(); i++)
    {
      Waypoint w = track.getWaypoint(i);
      list.append(w);

      Position p = w.getPosition();
      if (end.compareTo(p))
        break;
    }

    Track t(list);
    l.setTrack(t);
  }
  
}

void RunRecord::load(char *filename)
{
  load(QString(filename));
}

void RunRecord::load(QString filename)
{
  GarminDumpReader reader(filename);
  garmin_data *data = reader.get();

  if (data->type != data_Dlist)
  {
    qWarning("GarminRecord: unsuitable garmin_data type. Should be list.");
    garmin_free_data(data);
    return;
  }

  garmin_list *list = (garmin_list*)(data->data);
  initFromData(list);
  garmin_free_data(data);
}

QString RunRecord::toString()
{
  QString string("");
  string += "[ RUN_RECORD";
  string += " track index:";
  string += QVariant(track_index).toString();
  string += " track:";
  string += track.toString();

  Lap l;
  foreach(l, laps)
  {
    string += "\n ";
    string += l.toString();
  }
  string += " first lap index:";
  string += QVariant(first_lap_index).toString();
  string += " last lap index:";
  string += QVariant(last_lap_index).toString();
  string += " sport type:";
  string += QVariant(sport_type).toString();
  string += " program type:";
  string += QVariant(program_type).toString();
  string += " multisport:";
  string += QVariant(multisport).toString();

  string += " ]";
  return string;
}

QString RunRecord::toKMLPath()
{

  QString kml(""
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
"  <Document>\n");

  Waypoint w = track.getWaypoint(0);
  QString date = w.getDate().toString();

  //
  // NAME
  //
  if (sport_type == 0)
    kml += XMLTag("name", "Run on " + date);
  else if (sport_type == 1)
    kml += XMLTag("name", "Bike ride on " + date);
  else
    kml += XMLTag("name", "Activity on " + date);

  //
  // DESCRIPTION
  //
  QString desc("Map of ");
  if (sport_type == 0)
    desc += "run ";
  else if (sport_type == 1)
    desc += "bike ride ";
  else
    desc += "activity ";
  desc += "taking place on " + date;
  desc += ".\n\n  Generated by Garmin-View.";
  kml += XMLTag("description", desc);

  //
  // KML GENERATION
  //
  kml += ""
"    <Style id=\"yellowLineGreenPoly\">\n"
"      <LineStyle>\n"
"        <color>7f00ffff</color>\n"
"        <width>4</width>\n"
"      </LineStyle>\n"
"      <PolyStyle>\n"
"        <color>7f00ff00</color>\n"
"      </PolyStyle>\n"
"    </Style>\n"
"    <Placemark>\n";

  kml += ""
"      <styleUrl>#yellowLineGreenPoly</styleUrl>\n";


  Lap l;
  int j = 0;
  foreach(l, laps)
  {
    kml += "<Placemark>\n";

    kml += XMLTag("name", "Lap " + QVariant(j++).toString());
    kml += XMLTag("description", desc);

    kml += ""
"      <MultiGeometry>\n"
"       <LineString>\n"
"         <extrude>1</extrude>\n"
"         <tessellate>1</tessellate>\n"
"         <altitudeMode>absolute</altitudeMode>\n"
"         <coordinates> \n";

    Track t = l.getTrack();
    int i;
    int size = t.numWaypoints();
    for (i = 0; i < size; i++)
    {
      w = t.getWaypoint(i);
      Position p = w.getPosition();

      if (p.isValid())
      {
        // lon, lat \n
        kml += QVariant(p.getLon()).toString();
        kml += ", ";
        kml += QVariant(p.getLat()).toString();
        kml += "\n";
      }
    }


    kml += ""
"         </coordinates>\n"
"       </LineString>\n"
"      </MultiGeometry>\n"
"     </Placemark>\n";
  }


  kml += ""
"  </Document>\n"
"</kml>\n";

  return kml;
}

QString RunRecord::XMLTag(QString tag, QString text)
{
  return QString("<" + tag + ">" + text + "</" + tag + ">\n");
}

QDate RunRecord::getDate()
{
  return laps.value(0).getDate();
}

QTime RunRecord::getTime()
{
  return laps.value(0).getStart_time();
}

Track RunRecord::getTrack()
{
  return track;
}